package at.fhj.mobsecdev.cookit.webrequests;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import at.fhj.mobsecdev.cookit.R;
import at.fhj.mobsecdev.cookit.model.Ingredient;
import at.fhj.mobsecdev.cookit.model.Recipe;
import at.fhj.mobsecdev.cookit.util.Constants;
import at.fhj.mobsecdev.cookit.util.LoadingIndicator;
import at.fhj.mobsecdev.cookit.util.MultipartEntity;
import at.fhj.mobsecdev.cookit.util.Tuple;

/**
 * Call upload recipe web service
 */
public class UploadRecipeAsyncWebCall extends AsyncTask<Recipe, Void, Tuple<Integer, String>> {

	private SharedPreferences sharedPreferences;
	private Upload activity;
	private ProgressDialog dialog;
	private Context context;
	
	public UploadRecipeAsyncWebCall(Upload upload, SharedPreferences sharedPreferences, Activity activity)
	{
		this.activity = upload;
		this.sharedPreferences = sharedPreferences;
		this.context = activity;
	}
	
	protected void onPreExecute() {
	    dialog = new LoadingIndicator(context).createIndicator();
	    dialog.show();
	}
	
	/**
	 * Calls web service
	 * @return Tuple, that contains HTTP status code and return message (entity)
	 */
	@Override
	protected Tuple<Integer, String> doInBackground(Recipe... recipe) {

		HttpResponse response = null;
		
		Recipe recipeToUpload = recipe[0];
		InputStream in = null;
		ByteArrayOutputStream stream = null;

		DefaultHttpClient httpclient = new DefaultHttpClient();

		try {
			String webServiceUrl = WebServiceUrls.REST_URL + WebServiceUrls.UPLOAD_RECIPE;
			
			/* Include credentials */
			String timestamp = GetTimestampWebCall.getTimestamp();

			String username = sharedPreferences.getString(Constants.PREFERENCE_USERNAME, "");
			String passwordHash = sharedPreferences.getString(Constants.PREFERENCE_PASSWORDHASH, "");
			
			HttpPost httppost = new HttpPost(webServiceUrl);

			/* Build Http-Form */
			MultipartEntity reqEntity = new MultipartEntity();

			reqEntity.addPart("username", username);
			reqEntity.addPart("passwordHash", HashUtils.hashCredentials(username, passwordHash, timestamp));
			reqEntity.addPart("name", recipeToUpload.getName());
			reqEntity.addPart("cookingInstruction", recipeToUpload.getCookingInstruction());
			reqEntity.addPart("difficulty", recipeToUpload.getDifficulty());
			reqEntity.addPart("isVegetarian", Boolean.toString(recipeToUpload.isVegetarian()));
			reqEntity.addPart("ownerUsername", username);

			/* Add Ingredients as JSON array */
			JSONArray jsonRecipeArray = new JSONArray();
			for(Ingredient ingredient : recipeToUpload.getIngredients())
			{
				jsonRecipeArray.put(ingredient.toJSON());
			}
			reqEntity.addPart("ingredients", jsonRecipeArray.toString()); //send ingredients as JSON-String
			
			/* Include image */
			if (recipeToUpload.getImageFilePath() != null) {			
				Bitmap bitmap = shrinkBitmap(recipeToUpload.getImageFilePath(), 500, 500);
				
				stream = new ByteArrayOutputStream();
				bitmap.compress(Bitmap.CompressFormat.JPEG, 10, stream);
				in = new ByteArrayInputStream(stream.toByteArray());
				
				reqEntity.addPart("image", System.currentTimeMillis() + ".jpg", in);
			}

			httppost.setEntity(reqEntity);

			Log.i("UploadRecipe", "request " + httppost.getRequestLine());
			try {
				response = httpclient.execute(httppost);
			} catch (ClientProtocolException e) {
				return null;
			} catch (IOException e) {
				return null;
			}
			try {
				if (response != null)
					Log.i("UploadRecipe", "response "
							+ response.getStatusLine().toString());
			} finally {

			}
		} finally {

		}

		if (in != null) {
			try {
				in.close();
			} catch (IOException e) {
				return null;
			}
		}

		if (stream != null) {
			try {
				stream.close();
			} catch (IOException e) {
				return null;
			}
		}

		try {
			/* If call was successful, return status code + entity, otherwise null */
			return response != null ? new Tuple<Integer, String>(response.getStatusLine().getStatusCode(), EntityUtils.toString(response.getEntity())) : null;
		} catch (Exception e) {
			return null;
		}
	}
	
	@Override
	protected void onPostExecute(Tuple<Integer, String> result) {
		super.onPostExecute(result);
		if (dialog.isShowing()) {
			dialog.dismiss();
		}
		if(result == null) { //Call was not successful
			activity.uploadFailed(context.getResources().getString(R.string.unknown_reason));
			return;
		}
		if(result.x == HttpStatus.SC_OK) //Call was not successful, upload was successful
		{
			activity.uploadSuccessful();
		}
		else if(result.x == 400) //Call was not successful, upload was not successful
		{
			activity.uploadFailed(result.y);
		}
		else {   //Call was not successful, upload was not successful (unknown reason)
			activity.uploadFailed(context.getResources().getString(R.string.unknown_reason));
		}
		
	}
	
	/**
	 * Interface, which specifies the methods that are called after the webservice call.
	 */
	public interface Upload
	{
		void uploadSuccessful();
		
		void uploadFailed(String errorMessage);		
	}
	
	/* Utility */
	Bitmap shrinkBitmap(String file, int width, int height){

		 BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
		    bmpFactoryOptions.inJustDecodeBounds = true;
		    Bitmap bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);

		    int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)height);
		    int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)width);

		    if (heightRatio > 1 || widthRatio > 1)
		    {
		     if (heightRatio > widthRatio)
		     {
		      bmpFactoryOptions.inSampleSize = heightRatio;
		     } else {
		      bmpFactoryOptions.inSampleSize = widthRatio; 
		     }
		    }

		    bmpFactoryOptions.inJustDecodeBounds = false;
		    bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);
		 return bitmap;
		}

}
